
#include "lib\bit.h"
#include "jxos_public.h"
#include "../PHY/jsnet_phy.h"
#include "jsnet_dlk.h"
#include "dlk_frame.h"
#include "dlk_send_receive.h"
#include "dlk_cmd.h"
#include "dlk_parameter.h"
#include "dlk_encrypt.h"
#include "dlk_debug_print.h"

/*********************************
the dlk_primitives provide interfaces that can be called by n+1 layer
each interface can execute one DLK behavior
a dlk_primitives(DLK behavior) may contain one or more dlk_cmd
the dlk_primitives will handle the response of these dlk_cmd and notifies the results to n+1 layer 
*********************************/

#define DLK_SCANING_TIME 			5000
#define DLK_CONNECTING_TIME 		5000
#define DLK_ANNOUNCING_TIME 		5000
#define DLK_DATA_POLLING_TIME 		3000
#define DLK_DATA_SENDING_TIME 		3000
static swtime_type dlk_primitives_handler_software_timer_id;

static uint8_t send_target_node_addr_buff[FRAME_LONG_ADDR_LEN];
static uint8_t send_target_node_addr_len_buff;
static uint8_t save_target_node_addr(uint8_t* target_addr, uint8_t addr_type)
{
	send_target_node_addr_len_buff = addr_type_to_addr_len(addr_type);

	if(send_target_node_addr_len_buff == 0xff){
		return 0;
	}
	return node_addr_set(send_target_node_addr_buff, target_addr, addr_type);
}

static void print_addr(uint8_t* p_addr, uint8_t addr_type)
{
	dlk_debug_print_str("0x");
	dlk_debug_print_hex(p_addr[0]);
	if(addr_type == FRAME_LONG_ADDR){
	    dlk_debug_print_hex(p_addr[1]);
	}
}

static void wait_response_time(uint16_t wait_time)
{
	sys_svc_software_timer_set_time(dlk_primitives_handler_software_timer_id, wait_time);
	sys_svc_software_timer_restart(dlk_primitives_handler_software_timer_id);
}
#define stop_waitting_response()	sys_svc_software_timer_stop(dlk_primitives_handler_software_timer_id)

/********************************************************************************************/
/********************************************************************************************/
#define is_receive_broadcast_frame() (broadcast_addr_check(receive_target_node_addr,receive_frame_struct.head_byte.target_addr_type))
static FRAME_STRUCT receive_frame_struct;
static uint8_t receive_frame_playload[FRAME_PAYLOAD_MAX_LEN+1];
static uint8_t receive_target_node_addr[FRAME_LONG_ADDR_LEN];
static uint8_t receive_source_node_addr[FRAME_LONG_ADDR_LEN];
static void dlk_primitives_receive_callback(uint8_t* receive_data, uint8_t data_len)
{
	uint8_t* send_frame_buff;

	dlk_debug_print_str("dlk_primitives_receive_callback\r\n");

	//decrypt------------------------------------
	if((deframe_is_encrypted(receive_data))&&
	(decrypt(receive_data, &data_len) == 0)){
		dlk_debug_print_str("decrypt fail!\r\n");
		return;
	}

	//verf--------------------------------------
    if(deframe(receive_data, data_len,
			&receive_frame_struct,
			receive_frame_playload,
			receive_target_node_addr,
			receive_source_node_addr)== 0){
		dlk_debug_print_str("deframe fail!\r\n");
		return;
	}

	dlk_debug_print_str("deframe ok!!\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_DONGLE)
	dlk_debug_print_data_stream_in_hex(receive_data, data_len);
	dlk_debug_print_str("\r\n");

	dlk_debug_print_str("playload:");
	dlk_debug_print_data_stream_in_hex(receive_frame_playload, receive_frame_struct.playload_len);
	dlk_debug_print_str("\r\n");

	dlk_debug_print_str("encrypted:");
	dlk_debug_print_int(receive_frame_struct.head_byte.encrypted);
	dlk_debug_print_str("\t");

	dlk_debug_print_str("need_ack:");
	dlk_debug_print_int(receive_frame_struct.head_byte.need_ack);
	dlk_debug_print_str("\t");

	dlk_debug_print_str("frame_count:");
	dlk_debug_print_int(receive_frame_struct.frame_count);
	dlk_debug_print_str("\r\n");
#endif
	//repeat_filt-------------------------------

	//addr conflicts----------------------------

	//neighbor_node discover--------------------
	//if(decrypt(receive_data, &data_len) == 1){
	//	neighbor_node_map_add();
	//}

	//target_node_addr--------------------------
	dlk_debug_print_str("receive_target_node_addr:");
	print_addr(receive_target_node_addr, receive_frame_struct.head_byte.target_addr_type);
    dlk_debug_print_str("\t");
	dlk_debug_print_str("receive_source_node_addr:");
	print_addr(receive_source_node_addr, receive_frame_struct.head_byte.source_addr_type);
    dlk_debug_print_str("\r\n");
#if (JSNET_DLK_DEVICE_TYPE != JSNET_DLK_DEVICE_TYPE_DONGLE)
	if((node_addr_match(receive_target_node_addr,
		local_node_addr_get(receive_frame_struct.head_byte.target_addr_type),
		receive_frame_struct.head_byte.target_addr_type) == 0)
		&&(is_receive_broadcast_frame() == 0)){
		return;
	}
#endif

	//cmd_type-----------------------------------
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_DONGLE)
	switch(receive_frame_struct.head_byte.frame_type){
		case FRAME_DATA:
		break;
		default:
			dlk_debug_print_str("Unknow Cmd");
		break;
	}
	return;
#endif
	/******************************
	dlk cmd rec step
	1.check dlk state
	2.check dlk waitting
	3.check source addr
	4.check target addr
	5.check decrypt
	6.check discoverable flag
	7.stop waitting response
	8.ack
	******************************/
	switch(receive_frame_struct.head_byte.frame_type){
		case FRAME_DATA:
			dlk_debug_print_str("FRAME_DATA\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			if((dlk_state_get() == DLK_STATE_STARTED)
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
			if((dlk_state_get() == DLK_STATE_CONNECTED)
#else
			if((dlk_state_get() == 0)
#endif
			&&(deframe_is_encrypted(receive_data) == 1)){
				if(is_receive_broadcast_frame() == 0){
					dlk_cmd_ack(receive_source_node_addr,
						receive_frame_struct.head_byte.source_addr_type,
						receive_frame_struct.frame_count);
				}
				if(jsnet_dlk_indication_data_receive != 0){
					jsnet_dlk_indication_data_receive(receive_source_node_addr,
						addr_type_to_addr_len(receive_frame_struct.head_byte.source_addr_type),
						receive_frame_playload,
						receive_frame_struct.playload_len);
				}
			}
		break;

		case FRAME_CMD_OPEN_NODE_REQUEST:
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			dlk_debug_print_str("FRAME_CMD_OPEN_NODE_REQUEST\r\n");
			if((dlk_state_get() == DLK_STATE_STARTED)
				&&(receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&(is_receive_broadcast_frame() == 1)
				&&(deframe_is_encrypted(receive_data) == 0)
				&&(discoverable_falg_get() == 1)){
				dlk_debug_print_str("dlk_cmd_open_node_response\r\n");
				dlk_cmd_open_node_response(receive_source_node_addr,
					receive_frame_struct.head_byte.source_addr_type);
			}
#endif
		break;

		case FRAME_CMD_OPEN_NODE_RESPONSE:
			dlk_debug_print_str("FRAME_CMD_OPEN_NODE_RESPONSE\r\n");
			if((dlk_state_get() == DLK_STATE_SCANING)
				&&(receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&((is_receive_broadcast_frame() == 0))	//not broadcast_addr
				&&(deframe_is_encrypted(receive_data) == 0)){
				dlk_debug_print_str("find open node: ");
				print_addr(receive_source_node_addr, FRAME_LONG_ADDR);
				dlk_debug_print_str("\r\n");
				if(jsnet_dlk_confirm_scan != 0){
					jsnet_dlk_confirm_scan(receive_source_node_addr, FRAME_LONG_ADDR_LEN);
				}
			}
		break;

		case FRAME_CMD_LINK_REQUEST:
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			dlk_debug_print_str("FRAME_CMD_LINK_REQUEST\r\n");
			if((dlk_state_get() == DLK_STATE_STARTED)
				&&(receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&((is_receive_broadcast_frame() == 0)) //not broadcast_addr
				&&(deframe_is_encrypted(receive_data) == 0)
				&&(discoverable_falg_get() == 1)){
				if(jsnet_dlk_indication_connect != 0){
					if(jsnet_dlk_indication_connect(receive_source_node_addr, FRAME_LONG_ADDR_LEN)
						== 0){
						break;	//no response
					}
				}
				dlk_debug_print_str("send link response\r\n");
				dlk_cmd_link_response(receive_source_node_addr,
					receive_frame_struct.head_byte.source_addr_type, key_get());
			}
#endif
		break;

		case FRAME_CMD_LINK_RESPONSE:
			dlk_debug_print_str("FRAME_CMD_LINK_RESPONSE\r\n");
			if((dlk_state_get() == DLK_STATE_CONNECTING)
				&&(receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&((is_receive_broadcast_frame() == 0))	//not broadcast_addr
				&&(deframe_is_encrypted(receive_data) == 0)){
				dlk_debug_print_str("rec link response, updata dlk state, get key:0x");
				dlk_debug_print_hex(receive_frame_playload[0]);
				dlk_debug_print_str("\r\n");
				key_set(receive_frame_playload[0]);
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				dlk_state_set(DLK_STATE_CONNECTED);
#endif
				stop_waitting_response();
				if(jsnet_dlk_confirm_connect != 0){
					jsnet_dlk_confirm_connect(receive_source_node_addr, FRAME_LONG_ADDR_LEN, 1);
				}
			}
		break;

		case FRAME_CMD_DEVICE_NOTIFY:
			dlk_debug_print_str("FRAME_CMD_DEVICE_NOTIFY\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			if((receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&(deframe_is_encrypted(receive_data) == 1)){
				if(is_receive_broadcast_frame() == 1){
					if(jsnet_dlk_indication_announce != 0){
						jsnet_dlk_indication_announce(receive_source_node_addr, FRAME_LONG_ADDR_LEN);
					}
					dlk_debug_print_str("send device notify response\r\n");
					dlk_cmd_device_notify(receive_source_node_addr, FRAME_LONG_ADDR,
						local_node_addr_get(FRAME_SHORT_ADDR), JSNET_DLK_DEVICE_TYPE);
				}
				else{
//					neighbor_node_map_add();
					if(jsnet_dlk_confirm_announce != 0){
						jsnet_dlk_confirm_announce(receive_source_node_addr, FRAME_LONG_ADDR_LEN);
					}
				}
			}
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
			if((receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
				&&(deframe_is_encrypted(receive_data) == 1)
				&&(is_receive_broadcast_frame() == 0)){
//				neighbor_node_map_add();
				if(jsnet_dlk_confirm_announce != 0){
					jsnet_dlk_confirm_announce(receive_source_node_addr, FRAME_LONG_ADDR_LEN);
				}
			}
#endif
		break;

		case FRAME_CMD_UNLINK_NOTIFY:
			dlk_debug_print_str("FRAME_CMD_UNLINK_NOTIFY\r\n");
			if((receive_frame_struct.head_byte.source_addr_type == FRAME_LONG_ADDR)
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				&&(dlk_state_get() == DLK_STATE_CONNECTED)
#endif
				&&(deframe_is_encrypted(receive_data) == 1)){
				dlk_debug_print_str("rec unlink notify\r\n");
				//del neighbor;
				if(jsnet_dlk_indication_disconnect != 0){
					jsnet_dlk_indication_disconnect(receive_source_node_addr, FRAME_LONG_ADDR_LEN);
				}
			}
			break;

		case FRAME_CMD_DATA_REQUEST:
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			dlk_debug_print_str("FRAME_CMD_DATA_REQUEST\r\n");
			if((deframe_is_encrypted(receive_data) == 1)
				&&(is_receive_broadcast_frame() == 0)){
				dlk_cmd_ack(receive_source_node_addr,
					receive_frame_struct.head_byte.source_addr_type,
					receive_frame_struct.frame_count);
				if(jsnet_dlk_indication_data_poll != 0){
					jsnet_dlk_indication_data_poll(receive_source_node_addr,
					addr_type_to_addr_len(receive_frame_struct.head_byte.source_addr_type));
				}
			}
#endif
			break;

		case FRAME_CMD_ACK:
			dlk_debug_print_str("FRAME_CMD_ACK\r\n");
			if(dlk_send_is_repeatting() == 1){
				dlk_debug_print_str("dlk_send_is_repeatting\r\n");
				send_frame_buff = dlk_send_buff_get(&data_len);
				if((deframe_get_frame_count(send_frame_buff) == receive_frame_playload[0])
				&&(is_receive_broadcast_frame() == 0)){		//no ack when is_receive_broadcast_frame
					dlk_debug_print_str("ack check ok! stop repeat\r\n");
					dlk_send_stop_repeat();

					if(dlk_state_get() == DLK_STATE_DATA_POLLING){
						dlk_debug_print_str("ACK FOR FRAME_CMD_DATA_POLLING\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
						dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
						dlk_state_set(DLK_STATE_CONNECTED);
#endif
						stop_waitting_response();
						if(jsnet_dlk_confirm_data_poll != 0){
							jsnet_dlk_confirm_data_poll(receive_source_node_addr,
							addr_type_to_addr_len(receive_frame_struct.head_byte.source_addr_type), 1);
						}
					}

					if(dlk_state_get() == DLK_STATE_DATA_SENDING){
						dlk_debug_print_str("ACK FOR FRAME_CMD_DATA_SENDING\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
						dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
						dlk_state_set(DLK_STATE_CONNECTED);
#endif
						stop_waitting_response();
						if(jsnet_dlk_confirm_data_send != 0){
							jsnet_dlk_confirm_data_send(receive_source_node_addr,
							addr_type_to_addr_len(receive_frame_struct.head_byte.source_addr_type), 1);
						}
					}
				}
			}
		break;

		default:
			dlk_debug_print_str("Unknow Cmd");
		break;
	}
}

/***************************************************************/
void dlk_primitives_init(void)
{
	dlk_receive_callbck_register(dlk_primitives_receive_callback);
	dlk_primitives_handler_software_timer_id = sys_svc_software_timer_new();
	local_node_addr_set(broadcast_addr_get(), FRAME_SHORT_ADDR);
}

void dlk_primitives_handler(void)
{
	if(sys_svc_software_timer_check_overtime(dlk_primitives_handler_software_timer_id) == 1){
#if(JSNET_DLK_DEVICE_TYPE != JSNET_DLK_DEVICE_TYPE_STD_NODE)
		jsnet_phy_request_rx_disable();
#endif
		stop_waitting_response();
		switch(dlk_state_get()){
			case DLK_STATE_SCANING:
				dlk_debug_print_str("dlk scan finish\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				dlk_state_set(DLK_STATE_NOT_CONNECTED);
#endif
				if(jsnet_dlk_confirm_scan != 0){
					jsnet_dlk_confirm_scan(0, 0);
				}
			break;

			case DLK_STATE_CONNECTING:
				dlk_debug_print_str("dlk connect fail\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				dlk_state_set(DLK_STATE_NOT_CONNECTED);
#endif
				dlk_debug_print_str("connect confirm addr:");
				print_addr(send_target_node_addr_buff,
					addr_len_to_addr_type(send_target_node_addr_len_buff));
				if(jsnet_dlk_confirm_connect != 0){
					jsnet_dlk_confirm_connect(send_target_node_addr_buff,
					send_target_node_addr_len_buff, 0);
				}
			break;

			case DLK_STATE_DATA_POLLING:
				dlk_debug_print_str("dlk polling fail\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				dlk_state_set(DLK_STATE_CONNECTED);
#endif
				dlk_debug_print_str("polling confirm addr:");
				print_addr(send_target_node_addr_buff,
					addr_len_to_addr_type(send_target_node_addr_len_buff));
				if(jsnet_dlk_confirm_data_poll != 0){
					jsnet_dlk_confirm_data_poll(send_target_node_addr_buff,
					send_target_node_addr_len_buff, 0);
				}
			break;

			case DLK_STATE_DATA_SENDING:
				dlk_debug_print_str("dlk sending fail\r\n");
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
				dlk_state_set(DLK_STATE_CONNECTED);
#endif
				dlk_debug_print_str("sending confirm addr:");
				print_addr(send_target_node_addr_buff,
					addr_len_to_addr_type(send_target_node_addr_len_buff));
				if(jsnet_dlk_confirm_data_send != 0){
					jsnet_dlk_confirm_data_send(send_target_node_addr_buff,
					send_target_node_addr_len_buff, 0);
				}
			break;

			default:
				dlk_debug_print_str("unhandler dlk state");
				dlk_debug_print_int(dlk_state_get());
				dlk_debug_print_str("\r\n");
			break;
		}
	}
}

/***************************************************************/
/******************************
dlk cmd send step
1.check dlk state
2.check dlk waitting
3.check target addr
******************************/
uint8_t jsnet_dlk_request_scan(void)
{
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
	if(dlk_state_get() != DLK_STATE_STARTED){
		return 0;
	}
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() != DLK_STATE_NOT_CONNECTED){
		return 0;
	}
#endif

	if(dlk_cmd_open_node_request() == 0){
		return 0;
	}

	dlk_debug_print_str("jsnet_dlk_request_scan\r\n");

	dlk_state_set(DLK_STATE_SCANING);
	wait_response_time(DLK_SCANING_TIME);

	return 1;
}
void (*jsnet_dlk_confirm_scan)(uint8_t* open_node_adddr, uint8_t open_node_adddr_len) = 0;
//open_node_adddr_len = 0; open_node_adddr = 0; -->finish

/******************************/
uint8_t jsnet_dlk_request_connect(uint8_t* target_node_addr, uint8_t target_node_addr_len)
{
	if(target_node_addr == 0){
		return 0;
	}

#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
	if(dlk_state_get() != DLK_STATE_STARTED){
		return 0;
	}
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() != DLK_STATE_NOT_CONNECTED){
		return 0;
	}
#endif

	if(target_node_addr_len == FRAME_LONG_ADDR_LEN){
		target_node_addr_len = FRAME_LONG_ADDR;
	}
	else{
		return 0;
	}

	if(dlk_cmd_link_request(target_node_addr, target_node_addr_len) == 0){
		return 0;
	}
	if(save_target_node_addr(target_node_addr, target_node_addr_len) == 0){
		return 0;
	}

	dlk_debug_print_str("jsnet_dlk_request_connect\r\n");

	dlk_state_set(DLK_STATE_CONNECTING);
	wait_response_time(DLK_CONNECTING_TIME);

	return 1;
}
void (*jsnet_dlk_confirm_connect)(uint8_t* confirm_node_adddr, uint8_t confirm_node_adddr_len, uint8_t success) = 0;
//success = 0 -->fail
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
uint8_t (*jsnet_dlk_indication_connect)(uint8_t* req_connect_node_adddr, uint8_t req_connect_node_adddr_len) = 0;
#endif

/******************************/
uint8_t jsnet_dlk_request_announce(uint8_t* target_node_addr, uint8_t target_node_addr_len)
{
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() == DLK_STATE_NOT_CONNECTED){
		return 0;
	}
#endif

	if(target_node_addr_len == FRAME_LONG_ADDR_LEN){
		target_node_addr_len = FRAME_LONG_ADDR;
	}
	else{
		return 0;
	}

	if(dlk_cmd_device_notify(target_node_addr, target_node_addr_len,
				local_node_addr_get(FRAME_SHORT_ADDR), JSNET_DLK_DEVICE_TYPE) == 0){
		return 0;
	}

	dlk_debug_print_str("jsnet_dlk_request_announce\r\n");

	return 1;
}
void (*jsnet_dlk_confirm_announce)(uint8_t* announce_node_adddr, uint8_t announce_node_adddr_len) = 0; //issr?
//announce_node_adddr = 0; announce_node_adddr_len = 0; -->finish
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
void (*jsnet_dlk_indication_announce)(uint8_t* announce_node_adddr, uint8_t announce_node_adddr_len) = 0;
#endif

/******************************/
uint8_t jsnet_dlk_request_disconnect(void)
{
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() == DLK_STATE_NOT_CONNECTED){
		return 0;
	}
#endif

	if(dlk_cmd_unlink_notify() == 0){
		return 0;
	}
	key_set(0);	//del key
	stop_waitting_response();

	dlk_debug_print_str("jsnet_dlk_request_disconnect\r\n");

#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
	dlk_state_set(DLK_STATE_STARTED);
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	dlk_state_set(DLK_STATE_NOT_CONNECTED);
#endif

	return 1;
}
void (*jsnet_dlk_indication_disconnect)(uint8_t* disconnect_node_adddr, uint8_t disconnect_node_adddr_len) = 0;

/******************************/
uint8_t jsnet_dlk_request_data_poll(uint8_t* target_node_addr, uint8_t target_node_addr_len)
{
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
	if(dlk_state_get() != DLK_STATE_STARTED){
		return 0;
	}
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() != DLK_STATE_CONNECTED){
		return 0;
	}
#endif

	target_node_addr_len = addr_len_to_addr_type(target_node_addr_len);
	if(target_node_addr_len == 0xff){
		return 0;
	}

	if(dlk_cmd_data_request(target_node_addr, target_node_addr_len) == 0){
		return 0;
	}
	if(save_target_node_addr(target_node_addr, target_node_addr_len) == 0){
		return 0;
	}

	dlk_debug_print_str("jsnet_dlk_request_data_poll\r\n");

	dlk_state_set(DLK_STATE_DATA_POLLING);
	wait_response_time(DLK_DATA_POLLING_TIME);

	return 1;
}
void (*jsnet_dlk_confirm_data_poll)(uint8_t* target_node_addr, uint8_t target_node_addr_len, uint8_t success) = 0;
//success = 0 -->fail
void (*jsnet_dlk_indication_data_poll)(uint8_t* req_node_addr, uint8_t req_node_addr_len) = 0;

/******************************/
uint8_t jsnet_dlk_request_data_send(uint8_t* target_node_addr, uint8_t target_node_addr_len,
								uint8_t* send_data, uint8_t send_data_len)
{
#if (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
	if(dlk_state_get() != DLK_STATE_STARTED){
		return 0;
	}
#elif (JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_REDUCED_NODE)
	if(dlk_state_get() != DLK_STATE_CONNECTED){
		return 0;
	}
#endif

	target_node_addr_len = addr_len_to_addr_type(target_node_addr_len);
	if(target_node_addr_len == 0xff){
		return 0;
	}

	if(dlk_data_send(target_node_addr, target_node_addr_len,
					send_data, send_data_len) == 0){
		return 0;
	}
	if(save_target_node_addr(target_node_addr, target_node_addr_len) == 0){
		return 0;
	}

	dlk_debug_print_str("jsnet_dlk_request_data_send\r\n");

	dlk_state_set(DLK_STATE_DATA_SENDING);
	wait_response_time(DLK_DATA_SENDING_TIME);

	return 1;
}
void (*jsnet_dlk_confirm_data_send)(uint8_t* target_node_addr, uint8_t target_node_addr_len, uint8_t success) = 0;
//success = 0 -->fail
void (*jsnet_dlk_indication_data_receive)(uint8_t* source_node_addr, uint8_t source_node_addr_len,
											uint8_t* receive_playload, uint8_t receive_playload_len) = 0;


